<?php


/**
 * This is the base class of Automatically Updateing Objects
 * The object is wrapped around an array of information for the object
 * Most functions are declared final to prevent abuse and to assure their use
 */

abstract class AbstractPhlame implements Phlame
{
    const MAPPER_ID = 'Phlame';
	const SUB_BINDER = 'group_id';
	public function getSubMapper() { return false; }
	const MODULE_BINDER = 'phlame_id';
	public function getModuleMapper() { return false; }
    
    private $_closed = false;
    
    private $_datakeys;
    
    private $id;
    
    protected $_Subs = array();
    protected $_Modules = array();
    
    public function __construct(array $data)
    {
        foreach ($data as $k => &$v) {
            $this->$k = &$v;
        }
        $this->_datakeys = array_keys($data);
        $this->onInit();
    }
    
    public function __toString()
    {
        return sprintf("%s#%s", get_class($this), $this->getID());
    }
    
    /**
	 * Hook on init() [construct]
	 * overwrite to extend the constructor
	 */
    protected function onInit()
    {}
    
    /**
     * Returns the (SQL-)ID of the Phlameobject
     * @return integer
     */
    public function getID()
    {
        return $this->id;
    }
    
    /**
     * Returns the Mapper of the Phlame
     * @return Mapper
     */
    public function getMapper()
    {
        return MapperRegistry::get(constant(get_class($this).'::MAPPER_ID'));
    }
    
    /**
     * Initiates the save procedure for the object.
     * Updates are no longer possible after calling this method
     * @return bool succes
     */
    final public function close()
    {
        if ($this->_closed)
        {
            return false;
        }
        if (defined('DEBUG')) printf('
Closing %s#%s
', get_class($this), $this->getID());
        $this->OnClose();
        $data = array('id' => $this->getID());
        foreach ($this as $p => $v) {
            if (in_array($p, $this->_datakeys, true)) {
                $data[$p] = $v;
            }
        }
        $this->_cleanUp();
        $this->getMapper()->inform($data);
        $this->_closed = true;
        return true;
    }
    
    /**
     * Returns the status of the closed flag
     * @return bool
     */
    final public function isClosed()
    {
        return $this->_closed;
    }
    
    public function kill()
    {
        $this->_closed = true;
        $this->_cleanUp();
        $this->getMapper()->delete($this->getID());
    }
    
    /**
	 * Hook on close()
	 * overwrite to extend the object close procedure
	 */
    protected function OnClose()
    {}
    
    public function __destruct()
    {
        if (defined('DEBUG')) printf('
Destroying %s#%s
', get_class($this), $this->getID());
        if (defined('THROW_EXCEPTION_ON_DESTRUCT')) {
            try {
            throw new DestroyException(sprintf('
Destroying %s#%s
', get_class($this), $this->getID()));
            } catch (DestroyException $e) {
                echo $e;
            }
            
}
        $this->close();
    }
    
    protected function _cleanUp()
    {
        foreach ($this->_Subs as $Sub) {
            $Sub->close();
        }
        $this->_Subs = array();
        foreach ($this->_Modules as $Module) {
            $Module->close();
        }
        $this->_Modules = array();
    }
    
    public function addSubs(array $Subs)
    {
        #if (!$this->getSubMapper()) {
        #    throw new PhlameException('Undefined SubMapper / Phlame doesn\'t support Subs');
        #}
    	$this->_Subs = $Subs + $this->_Subs;
    }    
    
    public function addModules(array $Ms)
    {
        #if (!$this->getModuleMapper()) {
        #    throw new PhlameException('Undefined ModuleMapper / Phlame doesn\'t support Modules');
        #}
        $this->_Modules = $Ms + $this->_Modules;
    }
    
}